/*
 * $Id: $
 */
package org.rcgwt.client.ui.grid.theme;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 
 * @author Olivier Oeuillot (latest modification by $Author: $)
 * @version $Revision: $ $Date: $
 */
public class CssStyle {

    private static final char SUFFIX_SEPARATOR = '-';

    private final CssStyle parent;

    private final String className;

    private String computedClassName;

    private Map<String, CssStyle> cacheSuffixes;

    private static Map<String, CssStyle> mainCache = new HashMap<String, CssStyle>();

    private CssStyle(String mainClass) {
        this.className = mainClass;
        this.parent = null;

        // Log.debug("Create mainClass '" + mainClass + "'");
    }

    private CssStyle(CssStyle parent, String suffix) {
        this.parent = parent;
        this.className = suffix;

        // Log.debug("Create suffix '" + suffix + "'");
    }

    public static CssStyle create(String mainClass) {
        CssStyle cssStyle = mainCache.get(mainClass);
        if (cssStyle != null) {
            return cssStyle;
        }

        cssStyle = new CssStyle(mainClass);
        mainCache.put(mainClass, cssStyle);

        return cssStyle;
    }

    public CssStyle addSuffix(String suffix) {
        assert suffix != null : "Suffix is null !";

        CssStyle cs;
        if (cacheSuffixes == null) {
            cacheSuffixes = new HashMap<String, CssStyle>();

        } else {
            cs = cacheSuffixes.get(suffix);

            if (cs != null) {
                return cs;
            }
        }

        cs = new CssStyle(this, suffix);

        cacheSuffixes.put(suffix, cs);

        return cs;
    }

    public CssStyle addSuffixes(String... suffixes) {

        CssStyle cs = this;
        for (String suffix : suffixes) {
            cs = cs.addSuffix(suffix);
        }

        return cs;
    }

    public String getClassName() {
        if (computedClassName != null) {
            return computedClassName;
        }

        // Log.debug("Compute classname of " + this);

        if (parent == null) {
            computedClassName = className;

            return computedClassName;
        }

        List<String> l = new ArrayList<String>(8);

        CssStyle cs = this;
        for (; cs.parent != null; cs = cs.parent) {
            l.add(cs.className);
        }

        String mainClass = cs.className;

        int lsize = l.size();
        if (lsize == 1) {
            computedClassName = mainClass + " " + mainClass + SUFFIX_SEPARATOR
                    + l.get(0);

            return computedClassName;
        }

        Collections.sort(l);

        int cpmx = 1 << lsize;

        StringBuilder sb = new StringBuilder(cpmx * 32);
        sb.append(mainClass);

        for (int i = 1; i < cpmx; i++) {

            sb.append(' ').append(mainClass);

            for (int j = 0; j < lsize; j++) {
                if (((i >> j) & 1) == 0) {
                    continue;
                }

                sb.append(SUFFIX_SEPARATOR).append(l.get(j));
            }
        }

        computedClassName = sb.toString();
        return computedClassName;
    }

    @Override
    public String toString() {
        return "[CssStyle class='" + className + "' parent='" + parent
                + "' computed='" + computedClassName + "']";
    }

}
